package org.libermundi.theorcs.core.tapestry.services.configuration;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.libermundi.theorcs.core.exceptions.ApplicationConfigurationException;
import org.libermundi.theorcs.core.util.IOHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PropertiesApplicationConfiguration extends AbstractApplicationConfiguration {
	private static final Logger logger = LoggerFactory.getLogger(PropertiesApplicationConfiguration.class);
	
	private static final String classpathHeader="classpath:";
	
	private final Properties _appConfig = new Properties();
	
	public PropertiesApplicationConfiguration(List<String> propertiesPaths) {
		fillProperties(_appConfig, buildProperties(propertiesPaths));
	}

	@Override
	public Object getObject(String key, Object defaultValue) {
		Object result;
		if(_appConfig.containsKey(key)) {
			result = _appConfig.get(key);
		} else {
			result = defaultValue;
		}
		if(result!=null){
			return result;
		}
		throw new ApplicationConfigurationException("The Key '" + key + "' is not defined in the Application Configuration, nor has a default value");
	}
	
	/*
	 * Private Methods
	 */
	
	private Properties buildProperties(List<String> propertiesPaths) {
		Properties result = new Properties();
		for (Iterator<String> iterator = propertiesPaths.iterator(); iterator.hasNext();) {
				InputStream propFIS = null;

				String propertiesPath = iterator.next();
				
				if(propertiesPath.startsWith(classpathHeader)) {
					String filePath = propertiesPath.substring(classpathHeader.length());
					while(filePath.startsWith("/")){
						filePath=filePath.substring(1);
					}
					Class<?> clazz = this.getClass(); 
					propFIS = clazz.getResourceAsStream(filePath);
					
					if(propFIS == null) {
						ClassLoader contextCL= Thread.currentThread().getContextClassLoader();
						propFIS = contextCL.getResourceAsStream(filePath);
					}
						
					if(propFIS == null) {
						logger.warn("File '" + filePath + "' was not found in the ClassPath");
					} else {
						logger.info("File '" + filePath + "' was found in the ClassPath");
					}
				} else {
					try {
						File propertiesFile = IOHelper.path2File(propertiesPath);
						if(!propertiesFile.exists()){
							throw new FileNotFoundException();
						}
						propFIS = new FileInputStream(propertiesFile);
						logger.info("File '" + propertiesPath + "' was found in the Filesystem");
					} catch(FileNotFoundException fnf) {
						logger.warn("File '" + propertiesPath + "' was not found in the Filesystem");
					} catch (IOException exception) {
						logger.error(exception.getMessage());
					}
				}
				
				if(propFIS != null) {
					try {
						Properties p = new Properties();
						p.load(propFIS);
						Enumeration<Object> e = p.keys();
						while(e.hasMoreElements()){
							String key = (String)e.nextElement();
							String value = p.getProperty(key);
							if(logger.isDebugEnabled()){
								if(result.containsKey(key)) {
									logger.debug("Configuration Key '{}' is overrided with value : '{}'",key,value);
								} else {
									logger.debug("Configuration Key '{}' is defined with value : '{}'",key,value);
								}
							}
							result.setProperty(key, value);
						}
						propFIS.close();
					} catch (IOException exception) {
						logger.error(exception.getMessage());
					} finally {
						try {
							propFIS.close();
						} catch (IOException e1) {
							logger.error(e1.getMessage());
						}
					}
				}


		}
		return result;
	}
	
	private static void fillProperties(Properties base, Properties in) {
		Enumeration<Object> e = in.keys();
		while(e.hasMoreElements()){
			String key = (String)e.nextElement();
			base.setProperty(key, in.getProperty(key));
		}
	}
	
}
